source: rtems-libbsd/freebsd/sys/kern/uipc_syscalls.c @ 8d5fc9d

55-freebsd-126-freebsd-12
Last change on this file since 8d5fc9d was e0b4edbd, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/18 at 14:42:44

Update to FreeBSD head 2018-11-15

Git mirror commit a18b0830c4be01b39489a891b63d6023ada6358a.

Update #3472.

  • Property mode set to 100644
File size: 47.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (c) 1982, 1986, 1989, 1990, 1993
7 *      The Regents of the University of California.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *      @(#)uipc_syscalls.c     8.4 (Berkeley) 2/21/94
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39#include <rtems/bsd/local/opt_capsicum.h>
40#include <rtems/bsd/local/opt_inet.h>
41#include <rtems/bsd/local/opt_inet6.h>
42#include <rtems/bsd/local/opt_ktrace.h>
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/capsicum.h>
47#include <sys/kernel.h>
48#include <sys/lock.h>
49#include <sys/mutex.h>
50#include <sys/sysproto.h>
51#include <sys/malloc.h>
52#include <sys/filedesc.h>
53#include <sys/proc.h>
54#include <sys/filio.h>
55#include <sys/jail.h>
56#include <sys/mbuf.h>
57#include <sys/protosw.h>
58#include <sys/rwlock.h>
59#include <sys/socket.h>
60#include <sys/socketvar.h>
61#include <sys/syscallsubr.h>
62#include <sys/uio.h>
63#include <sys/un.h>
64#include <sys/unpcb.h>
65#ifdef KTRACE
66#include <sys/ktrace.h>
67#endif
68#ifdef COMPAT_FREEBSD32
69#include <compat/freebsd32/freebsd32_util.h>
70#endif
71
72#include <net/vnet.h>
73
74#include <security/audit/audit.h>
75#include <security/mac/mac_framework.h>
76
77static int sendit(struct thread *td, int s, struct msghdr *mp, int flags);
78static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp);
79
80#ifndef __rtems__
81static int accept1(struct thread *td, int s, struct sockaddr *uname,
82                   socklen_t *anamelen, int flags);
83static int getsockname1(struct thread *td, struct getsockname_args *uap,
84                        int compat);
85static int getpeername1(struct thread *td, struct getpeername_args *uap,
86                        int compat);
87#else /* __rtems__ */
88struct getsockaddr_sockaddr {
89        struct sockaddr header;
90        char            data[SOCK_MAXADDRLEN - sizeof(struct sockaddr)];
91} __aligned(sizeof(long));
92
93static int getsockaddr(struct sockaddr **, const struct sockaddr *, size_t);
94static int kern_getsockname(struct thread *, int, struct sockaddr **,
95    socklen_t *);
96static int kern_listen(struct thread *, int, int);
97static int kern_setsockopt(struct thread *, int, int, int, const void *,
98    enum uio_seg, socklen_t);
99static int kern_shutdown(struct thread *, int, int);
100static int kern_socket(struct thread *, int, int, int);
101static int kern_socketpair(struct thread *, int, int, int, int *);
102#endif /* __rtems__ */
103static int sockargs(struct mbuf **, char *, socklen_t, int);
104
105#ifndef __rtems__
106/*
107 * Convert a user file descriptor to a kernel file entry and check if required
108 * capability rights are present.
109 * If required copy of current set of capability rights is returned.
110 * A reference on the file entry is held upon returning.
111 */
112int
113getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
114    struct file **fpp, u_int *fflagp, struct filecaps *havecapsp)
115{
116        struct file *fp;
117        int error;
118
119        error = fget_cap(td, fd, rightsp, &fp, havecapsp);
120        if (error != 0)
121                return (error);
122        if (fp->f_type != DTYPE_SOCKET) {
123                fdrop(fp, td);
124                if (havecapsp != NULL)
125                        filecaps_free(havecapsp);
126                return (ENOTSOCK);
127        }
128        if (fflagp != NULL)
129                *fflagp = fp->f_flag;
130        *fpp = fp;
131        return (0);
132}
133#else /* __rtems__ */
134static int
135rtems_bsd_getsock(int fd, struct file **fpp, u_int *fflagp)
136{
137        struct file *fp;
138        int error;
139
140        if ((uint32_t) fd < rtems_libio_number_iops) {
141                unsigned int flags;
142
143                fp = rtems_bsd_fd_to_fp(fd);
144                flags = rtems_libio_iop_hold(&fp->f_io);
145                if ((flags & LIBIO_FLAGS_OPEN) == 0) {
146                        rtems_libio_iop_drop(&fp->f_io);
147                        fp = NULL;
148                        error = EBADF;
149                } else if (fp->f_io.pathinfo.handlers != &socketops) {
150                        rtems_libio_iop_drop(&fp->f_io);
151                        fp = NULL;
152                        error = ENOTSOCK;
153                } else {
154                        if (fflagp != NULL) {
155                                *fflagp = rtems_bsd_libio_flags_to_fflag(
156                                    fp->f_io.flags);
157                        }
158
159                        error = 0;
160                }
161        } else {
162                fp = NULL;
163                error = EBADF;
164        }
165
166        *fpp = fp;
167
168        return (error);
169}
170
171#define getsock_cap(td, fd, rights, fpp, fflagp, havecapsp) rtems_bsd_getsock(fd, fpp, fflagp)
172#endif /* __rtems__ */
173
174/*
175 * System call interface to the socket abstraction.
176 */
177#if defined(COMPAT_43)
178#define COMPAT_OLDSOCK
179#endif
180
181#ifdef __rtems__
182static
183#endif /* __rtems__ */
184int
185sys_socket(struct thread *td, struct socket_args *uap)
186{
187
188        return (kern_socket(td, uap->domain, uap->type, uap->protocol));
189}
190
191int
192kern_socket(struct thread *td, int domain, int type, int protocol)
193{
194        struct socket *so;
195        struct file *fp;
196        int fd, error, oflag, fflag;
197
198        AUDIT_ARG_SOCKET(domain, type, protocol);
199
200        oflag = 0;
201        fflag = 0;
202        if ((type & SOCK_CLOEXEC) != 0) {
203                type &= ~SOCK_CLOEXEC;
204                oflag |= O_CLOEXEC;
205        }
206        if ((type & SOCK_NONBLOCK) != 0) {
207                type &= ~SOCK_NONBLOCK;
208                fflag |= FNONBLOCK;
209        }
210
211#ifdef MAC
212        error = mac_socket_check_create(td->td_ucred, domain, type, protocol);
213        if (error != 0)
214                return (error);
215#endif
216        error = falloc(td, &fp, &fd, oflag);
217        if (error != 0)
218                return (error);
219        /* An extra reference on `fp' has been held for us by falloc(). */
220        error = socreate(domain, &so, type, protocol, td->td_ucred, td);
221        if (error != 0) {
222                fdclose(td, fp, fd);
223        } else {
224                finit(fp, FREAD | FWRITE | fflag, DTYPE_SOCKET, so, &socketops);
225                if ((fflag & FNONBLOCK) != 0)
226                        (void) fo_ioctl(fp, FIONBIO, &fflag, td->td_ucred, td);
227                td->td_retval[0] = fd;
228        }
229#ifndef __rtems__
230        fdrop(fp, td);
231#endif /* __rtems__ */
232        return (error);
233}
234#ifdef __rtems__
235int
236socket(int domain, int type, int protocol)
237{
238        struct thread *td = rtems_bsd_get_curthread_or_null();
239        struct socket_args ua = {
240                .domain = domain,
241                .type = type,
242                .protocol = protocol
243        };
244        int error;
245
246        if (td != NULL) {
247                error = sys_socket(td, &ua);
248        } else {
249                error = ENOMEM;
250        }
251
252        if (error == 0) {
253                return td->td_retval[0];
254        } else {
255                rtems_set_errno_and_return_minus_one(error);
256        }
257}
258#endif /* __rtems__ */
259
260#ifdef __rtems__
261static int kern_bindat(struct thread *td, int dirfd, int fd,
262    struct sockaddr *sa);
263
264static
265#endif /* __rtems__ */
266int
267sys_bind(struct thread *td, struct bind_args *uap)
268{
269        struct sockaddr *sa;
270        int error;
271#ifdef __rtems__
272        struct getsockaddr_sockaddr gsa;
273        sa = &gsa.header;
274#endif /* __rtems__ */
275
276        error = getsockaddr(&sa, uap->name, uap->namelen);
277        if (error == 0) {
278                error = kern_bindat(td, AT_FDCWD, uap->s, sa);
279#ifndef __rtems__
280                free(sa, M_SONAME);
281#endif /* __rtems__ */
282        }
283        return (error);
284}
285#ifdef __rtems__
286int
287bind(int socket, const struct sockaddr *address, socklen_t address_len)
288{
289        struct thread *td = rtems_bsd_get_curthread_or_null();
290        struct bind_args ua = {
291                .s = socket,
292                .name = address,
293                .namelen = address_len
294        };
295        int error;
296
297        if (td != NULL) {
298                error = sys_bind(td, &ua);
299        } else {
300                error = ENOMEM;
301        }
302
303        return rtems_bsd_error_to_status_and_errno(error);
304}
305#endif /* __rtems__ */
306
307int
308kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
309{
310        struct socket *so;
311        struct file *fp;
312        int error;
313
314#ifdef CAPABILITY_MODE
315        if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD))
316                return (ECAPMODE);
317#endif
318
319        AUDIT_ARG_FD(fd);
320        AUDIT_ARG_SOCKADDR(td, dirfd, sa);
321        error = getsock_cap(td, fd, &cap_bind_rights,
322            &fp, NULL, NULL);
323        if (error != 0)
324                return (error);
325        so = fp->f_data;
326#ifdef KTRACE
327        if (KTRPOINT(td, KTR_STRUCT))
328                ktrsockaddr(sa);
329#endif
330#ifdef MAC
331        error = mac_socket_check_bind(td->td_ucred, so, sa);
332        if (error == 0) {
333#endif
334                if (dirfd == AT_FDCWD)
335                        error = sobind(so, sa, td);
336                else
337                        error = sobindat(dirfd, so, sa, td);
338#ifdef MAC
339        }
340#endif
341        fdrop(fp, td);
342        return (error);
343}
344
345#ifndef __rtems__
346static
347int
348sys_bindat(struct thread *td, struct bindat_args *uap)
349{
350        struct sockaddr *sa;
351        int error;
352#ifdef __rtems__
353        struct getsockaddr_sockaddr gsa;
354        sa = &gsa.header;
355#endif /* __rtems__ */
356
357        error = getsockaddr(&sa, uap->name, uap->namelen);
358        if (error == 0) {
359                error = kern_bindat(td, uap->fd, uap->s, sa);
360#ifndef __rtems__
361                free(sa, M_SONAME);
362#endif /* __rtems__ */
363        }
364        return (error);
365}
366#endif /* __rtems__ */
367
368#ifdef __rtems__
369static
370#endif /* __rtems__ */
371int
372sys_listen(struct thread *td, struct listen_args *uap)
373{
374
375        return (kern_listen(td, uap->s, uap->backlog));
376}
377
378int
379kern_listen(struct thread *td, int s, int backlog)
380{
381        struct socket *so;
382        struct file *fp;
383        int error;
384
385        AUDIT_ARG_FD(s);
386        error = getsock_cap(td, s, &cap_listen_rights,
387            &fp, NULL, NULL);
388        if (error == 0) {
389                so = fp->f_data;
390#ifdef MAC
391                error = mac_socket_check_listen(td->td_ucred, so);
392                if (error == 0)
393#endif
394                        error = solisten(so, backlog, td);
395                fdrop(fp, td);
396        }
397        return (error);
398}
399#ifdef __rtems__
400int
401listen(int socket, int backlog)
402{
403        struct thread *td = rtems_bsd_get_curthread_or_null();
404        struct listen_args ua = {
405                .s = socket,
406                .backlog = backlog
407        };
408        int error;
409
410        if (td != NULL) {
411                error = sys_listen(td, &ua);
412        } else {
413                error = ENOMEM;
414        }
415
416        return rtems_bsd_error_to_status_and_errno(error);
417}
418#endif /* __rtems__ */
419
420#ifdef __rtems__
421static int kern_accept4(struct thread *td, int s, struct sockaddr **name,
422    socklen_t *namelen, int flags, struct file **fp);
423#endif /* __rtems__ */
424/*
425 * accept1()
426 */
427static int
428accept1(td, s, uname, anamelen, flags)
429        struct thread *td;
430        int s;
431        struct sockaddr *uname;
432        socklen_t *anamelen;
433        int flags;
434{
435        struct sockaddr *name;
436        socklen_t namelen;
437        struct file *fp;
438        int error;
439
440        if (uname == NULL)
441                return (kern_accept4(td, s, NULL, NULL, flags, NULL));
442
443        error = copyin(anamelen, &namelen, sizeof (namelen));
444        if (error != 0)
445                return (error);
446
447        error = kern_accept4(td, s, &name, &namelen, flags, &fp);
448
449        if (error != 0)
450                return (error);
451
452        if (error == 0 && uname != NULL) {
453#ifdef COMPAT_OLDSOCK
454                if (flags & ACCEPT4_COMPAT)
455                        ((struct osockaddr *)name)->sa_family =
456                            name->sa_family;
457#endif
458                error = copyout(name, uname, namelen);
459        }
460        if (error == 0)
461                error = copyout(&namelen, anamelen,
462                    sizeof(namelen));
463        if (error != 0)
464                fdclose(td, fp, td->td_retval[0]);
465#ifndef __rtems__
466        fdrop(fp, td);
467#endif /* __rtems__ */
468        free(name, M_SONAME);
469        return (error);
470}
471#ifdef __rtems__
472int
473accept(int socket, struct sockaddr *__restrict address,
474    socklen_t *__restrict address_len)
475{
476        struct thread *td = rtems_bsd_get_curthread_or_null();
477        int error;
478
479        if (td != NULL) {
480                error = accept1(td, socket, address, address_len,
481                    ACCEPT4_INHERIT);
482        } else {
483                error = ENOMEM;
484        }
485
486        if (error == 0) {
487                return td->td_retval[0];
488        } else {
489                rtems_set_errno_and_return_minus_one(error);
490        }
491}
492#endif /* __rtems__ */
493
494#ifndef __rtems__
495int
496kern_accept(struct thread *td, int s, struct sockaddr **name,
497    socklen_t *namelen, struct file **fp)
498{
499        return (kern_accept4(td, s, name, namelen, ACCEPT4_INHERIT, fp));
500}
501#endif /* __rtems__ */
502
503int
504kern_accept4(struct thread *td, int s, struct sockaddr **name,
505    socklen_t *namelen, int flags, struct file **fp)
506{
507        struct file *headfp, *nfp = NULL;
508        struct sockaddr *sa = NULL;
509        struct socket *head, *so;
510        struct filecaps fcaps;
511        u_int fflag;
512        pid_t pgid;
513        int error, fd, tmp;
514
515        if (name != NULL)
516                *name = NULL;
517
518        AUDIT_ARG_FD(s);
519        error = getsock_cap(td, s, &cap_accept_rights,
520            &headfp, &fflag, &fcaps);
521        if (error != 0)
522                return (error);
523        head = headfp->f_data;
524        if ((head->so_options & SO_ACCEPTCONN) == 0) {
525                error = EINVAL;
526                goto done;
527        }
528#ifdef MAC
529        error = mac_socket_check_accept(td->td_ucred, head);
530        if (error != 0)
531                goto done;
532#endif
533        error = falloc_caps(td, &nfp, &fd,
534            (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps);
535        if (error != 0)
536                goto done;
537        SOCK_LOCK(head);
538        if (!SOLISTENING(head)) {
539                SOCK_UNLOCK(head);
540                error = EINVAL;
541                goto noconnection;
542        }
543
544        error = solisten_dequeue(head, &so, flags);
545        if (error != 0)
546                goto noconnection;
547
548        /* An extra reference on `nfp' has been held for us by falloc(). */
549        td->td_retval[0] = fd;
550
551        /* Connection has been removed from the listen queue. */
552        KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0);
553
554        if (flags & ACCEPT4_INHERIT) {
555                pgid = fgetown(&head->so_sigio);
556                if (pgid != 0)
557                        fsetown(pgid, &so->so_sigio);
558        } else {
559                fflag &= ~(FNONBLOCK | FASYNC);
560                if (flags & SOCK_NONBLOCK)
561                        fflag |= FNONBLOCK;
562        }
563
564        finit(nfp, fflag, DTYPE_SOCKET, so, &socketops);
565        /* Sync socket nonblocking/async state with file flags */
566        tmp = fflag & FNONBLOCK;
567        (void) fo_ioctl(nfp, FIONBIO, &tmp, td->td_ucred, td);
568        tmp = fflag & FASYNC;
569        (void) fo_ioctl(nfp, FIOASYNC, &tmp, td->td_ucred, td);
570        error = soaccept(so, &sa);
571        if (error != 0)
572                goto noconnection;
573        if (sa == NULL) {
574                if (name)
575                        *namelen = 0;
576                goto done;
577        }
578        AUDIT_ARG_SOCKADDR(td, AT_FDCWD, sa);
579        if (name) {
580                /* check sa_len before it is destroyed */
581                if (*namelen > sa->sa_len)
582                        *namelen = sa->sa_len;
583#ifdef KTRACE
584                if (KTRPOINT(td, KTR_STRUCT))
585                        ktrsockaddr(sa);
586#endif
587                *name = sa;
588                sa = NULL;
589        }
590noconnection:
591        free(sa, M_SONAME);
592
593        /*
594         * close the new descriptor, assuming someone hasn't ripped it
595         * out from under us.
596         */
597        if (error != 0)
598                fdclose(td, nfp, fd);
599
600        /*
601         * Release explicitly held references before returning.  We return
602         * a reference on nfp to the caller on success if they request it.
603         */
604done:
605        if (nfp == NULL)
606                filecaps_free(&fcaps);
607        if (fp != NULL) {
608                if (error == 0) {
609                        *fp = nfp;
610                        nfp = NULL;
611                } else
612                        *fp = NULL;
613        }
614#ifndef __rtems__
615        if (nfp != NULL)
616                fdrop(nfp, td);
617#endif /* __rtems__ */
618        fdrop(headfp, td);
619        return (error);
620}
621
622#ifndef __rtems__
623int
624sys_accept(td, uap)
625        struct thread *td;
626        struct accept_args *uap;
627{
628
629        return (accept1(td, uap->s, uap->name, uap->anamelen, ACCEPT4_INHERIT));
630}
631
632int
633sys_accept4(td, uap)
634        struct thread *td;
635        struct accept4_args *uap;
636{
637
638        if (uap->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
639                return (EINVAL);
640
641        return (accept1(td, uap->s, uap->name, uap->anamelen, uap->flags));
642}
643
644#ifdef COMPAT_OLDSOCK
645int
646oaccept(td, uap)
647        struct thread *td;
648        struct accept_args *uap;
649{
650
651        return (accept1(td, uap->s, uap->name, uap->anamelen,
652            ACCEPT4_INHERIT | ACCEPT4_COMPAT));
653}
654#endif /* COMPAT_OLDSOCK */
655#endif /* __rtems__ */
656
657#ifdef __rtems__
658static int kern_connectat(struct thread *td, int dirfd, int fd,
659    struct sockaddr *sa);
660
661static
662#endif /* __rtems__ */
663int
664sys_connect(struct thread *td, struct connect_args *uap)
665{
666        struct sockaddr *sa;
667        int error;
668#ifdef __rtems__
669        struct getsockaddr_sockaddr gsa;
670        sa = &gsa.header;
671#endif /* __rtems__ */
672
673        error = getsockaddr(&sa, uap->name, uap->namelen);
674        if (error == 0) {
675                error = kern_connectat(td, AT_FDCWD, uap->s, sa);
676#ifndef __rtems__
677                free(sa, M_SONAME);
678#endif /* __rtems__ */
679        }
680        return (error);
681}
682#ifdef __rtems__
683int
684connect(int socket, const struct sockaddr *address, socklen_t address_len)
685{
686        struct thread *td = rtems_bsd_get_curthread_or_null();
687        struct connect_args ua = {
688                .s = socket,
689                .name = address,
690                .namelen = address_len
691        };
692        int error;
693
694        if (td != NULL) {
695                error = sys_connect(td, &ua);
696        } else {
697                error = ENOMEM;
698        }
699
700        return rtems_bsd_error_to_status_and_errno(error);
701}
702#endif /* __rtems__ */
703
704int
705kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
706{
707        struct socket *so;
708        struct file *fp;
709        int error, interrupted = 0;
710
711#ifdef CAPABILITY_MODE
712        if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD))
713                return (ECAPMODE);
714#endif
715
716        AUDIT_ARG_FD(fd);
717        AUDIT_ARG_SOCKADDR(td, dirfd, sa);
718        error = getsock_cap(td, fd, &cap_connect_rights,
719            &fp, NULL, NULL);
720        if (error != 0)
721                return (error);
722        so = fp->f_data;
723        if (so->so_state & SS_ISCONNECTING) {
724                error = EALREADY;
725                goto done1;
726        }
727#ifdef KTRACE
728        if (KTRPOINT(td, KTR_STRUCT))
729                ktrsockaddr(sa);
730#endif
731#ifdef MAC
732        error = mac_socket_check_connect(td->td_ucred, so, sa);
733        if (error != 0)
734                goto bad;
735#endif
736        if (dirfd == AT_FDCWD)
737                error = soconnect(so, sa, td);
738        else
739                error = soconnectat(dirfd, so, sa, td);
740        if (error != 0)
741                goto bad;
742        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
743                error = EINPROGRESS;
744                goto done1;
745        }
746        SOCK_LOCK(so);
747        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
748                error = msleep(&so->so_timeo, &so->so_lock, PSOCK | PCATCH,
749                    "connec", 0);
750                if (error != 0) {
751                        if (error == EINTR || error == ERESTART)
752                                interrupted = 1;
753                        break;
754                }
755        }
756        if (error == 0) {
757                error = so->so_error;
758                so->so_error = 0;
759        }
760        SOCK_UNLOCK(so);
761bad:
762        if (!interrupted)
763                so->so_state &= ~SS_ISCONNECTING;
764        if (error == ERESTART)
765                error = EINTR;
766done1:
767        fdrop(fp, td);
768        return (error);
769}
770
771#ifndef __rtems__
772int
773sys_connectat(struct thread *td, struct connectat_args *uap)
774{
775        struct sockaddr *sa;
776        int error;
777#ifdef __rtems__
778        struct getsockaddr_sockaddr gsa;
779        sa = &gsa.header;
780#endif /* __rtems__ */
781
782        error = getsockaddr(&sa, uap->name, uap->namelen);
783        if (error == 0) {
784                error = kern_connectat(td, uap->fd, uap->s, sa);
785#ifndef __rtems__
786                free(sa, M_SONAME);
787#endif /* __rtems__ */
788        }
789        return (error);
790}
791#endif /* __rtems__ */
792
793int
794kern_socketpair(struct thread *td, int domain, int type, int protocol,
795    int *rsv)
796{
797        struct file *fp1, *fp2;
798        struct socket *so1, *so2;
799        int fd, error, oflag, fflag;
800
801        AUDIT_ARG_SOCKET(domain, type, protocol);
802
803        oflag = 0;
804        fflag = 0;
805        if ((type & SOCK_CLOEXEC) != 0) {
806                type &= ~SOCK_CLOEXEC;
807                oflag |= O_CLOEXEC;
808        }
809        if ((type & SOCK_NONBLOCK) != 0) {
810                type &= ~SOCK_NONBLOCK;
811                fflag |= FNONBLOCK;
812        }
813#ifdef MAC
814        /* We might want to have a separate check for socket pairs. */
815        error = mac_socket_check_create(td->td_ucred, domain, type,
816            protocol);
817        if (error != 0)
818                return (error);
819#endif
820        error = socreate(domain, &so1, type, protocol, td->td_ucred, td);
821        if (error != 0)
822                return (error);
823        error = socreate(domain, &so2, type, protocol, td->td_ucred, td);
824        if (error != 0)
825                goto free1;
826        /* On success extra reference to `fp1' and 'fp2' is set by falloc. */
827        error = falloc(td, &fp1, &fd, oflag);
828        if (error != 0)
829                goto free2;
830        rsv[0] = fd;
831        fp1->f_data = so1;      /* so1 already has ref count */
832        error = falloc(td, &fp2, &fd, oflag);
833        if (error != 0)
834                goto free3;
835        fp2->f_data = so2;      /* so2 already has ref count */
836        rsv[1] = fd;
837        error = soconnect2(so1, so2);
838        if (error != 0)
839                goto free4;
840        if (type == SOCK_DGRAM) {
841                /*
842                 * Datagram socket connection is asymmetric.
843                 */
844                 error = soconnect2(so2, so1);
845                 if (error != 0)
846                        goto free4;
847        } else if (so1->so_proto->pr_flags & PR_CONNREQUIRED) {
848                struct unpcb *unp, *unp2;
849                unp = sotounpcb(so1);
850                unp2 = sotounpcb(so2);
851                /*
852                 * No need to lock the unps, because the sockets are brand-new.
853                 * No other threads can be using them yet
854                 */
855                unp_copy_peercred(td, unp, unp2, unp);
856        }
857        finit(fp1, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp1->f_data,
858            &socketops);
859        finit(fp2, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp2->f_data,
860            &socketops);
861        if ((fflag & FNONBLOCK) != 0) {
862                (void) fo_ioctl(fp1, FIONBIO, &fflag, td->td_ucred, td);
863                (void) fo_ioctl(fp2, FIONBIO, &fflag, td->td_ucred, td);
864        }
865#ifndef __rtems__
866        fdrop(fp1, td);
867        fdrop(fp2, td);
868#endif /* __rtems__ */
869        return (0);
870free4:
871        fdclose(td, fp2, rsv[1]);
872#ifndef __rtems__
873        fdrop(fp2, td);
874#endif /* __rtems__ */
875free3:
876        fdclose(td, fp1, rsv[0]);
877#ifndef __rtems__
878        fdrop(fp1, td);
879#endif /* __rtems__ */
880free2:
881        if (so2 != NULL)
882                (void)soclose(so2);
883free1:
884        if (so1 != NULL)
885                (void)soclose(so1);
886        return (error);
887}
888
889#ifdef __rtems__
890static
891#endif /* __rtems__ */
892int
893sys_socketpair(struct thread *td, struct socketpair_args *uap)
894{
895#ifndef __rtems__
896        int error, sv[2];
897#else /* __rtems__ */
898        int error;
899        int *sv = uap->rsv;
900#endif /* __rtems__ */
901
902        error = kern_socketpair(td, uap->domain, uap->type,
903            uap->protocol, sv);
904        if (error != 0)
905                return (error);
906#ifndef __rtems__
907        error = copyout(sv, uap->rsv, 2 * sizeof(int));
908        if (error != 0) {
909                (void)kern_close(td, sv[0]);
910                (void)kern_close(td, sv[1]);
911        }
912#endif /* __rtems__ */
913        return (error);
914}
915#ifdef __rtems__
916int
917socketpair(int domain, int type, int protocol, int *socket_vector)
918{
919        struct thread *td = rtems_bsd_get_curthread_or_null();
920        struct socketpair_args ua = {
921                .domain = domain,
922                .type = type,
923                .protocol = protocol,
924                .rsv = socket_vector
925        };
926        int error;
927
928        if (td != NULL) {
929                error = sys_socketpair(td, &ua);
930        } else {
931                error = ENOMEM;
932        }
933
934        return rtems_bsd_error_to_status_and_errno(error);
935}
936#endif /* __rtems__ */
937
938#ifdef __rtems__
939static int
940kern_sendit( struct thread *td, int s, struct msghdr *mp, int flags,
941    struct mbuf *control, enum uio_seg segflg);
942#endif /* __rtems__ */
943static int
944sendit(struct thread *td, int s, struct msghdr *mp, int flags)
945{
946        struct mbuf *control;
947        struct sockaddr *to;
948        int error;
949#ifdef __rtems__
950        struct getsockaddr_sockaddr gto;
951        to = &gto.header;
952#endif /* __rtems__ */
953
954#ifdef CAPABILITY_MODE
955        if (IN_CAPABILITY_MODE(td) && (mp->msg_name != NULL))
956                return (ECAPMODE);
957#endif
958
959        if (mp->msg_name != NULL) {
960                error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
961                if (error != 0) {
962                        to = NULL;
963                        goto bad;
964                }
965                mp->msg_name = to;
966        } else {
967                to = NULL;
968        }
969
970        if (mp->msg_control) {
971                if (mp->msg_controllen < sizeof(struct cmsghdr)
972#ifdef COMPAT_OLDSOCK
973                    && mp->msg_flags != MSG_COMPAT
974#endif
975                ) {
976                        error = EINVAL;
977                        goto bad;
978                }
979                error = sockargs(&control, mp->msg_control,
980                    mp->msg_controllen, MT_CONTROL);
981                if (error != 0)
982                        goto bad;
983#ifdef COMPAT_OLDSOCK
984                if (mp->msg_flags == MSG_COMPAT) {
985                        struct cmsghdr *cm;
986
987                        M_PREPEND(control, sizeof(*cm), M_WAITOK);
988                        cm = mtod(control, struct cmsghdr *);
989                        cm->cmsg_len = control->m_len;
990                        cm->cmsg_level = SOL_SOCKET;
991                        cm->cmsg_type = SCM_RIGHTS;
992                }
993#endif
994        } else {
995                control = NULL;
996        }
997
998        error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE);
999
1000bad:
1001#ifndef __rtems__
1002        free(to, M_SONAME);
1003#endif /* __rtems__ */
1004        return (error);
1005}
1006
1007int
1008kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
1009    struct mbuf *control, enum uio_seg segflg)
1010{
1011        struct file *fp;
1012        struct uio auio;
1013        struct iovec *iov;
1014        struct socket *so;
1015#ifndef __rtems__
1016        cap_rights_t *rights;
1017#endif /* __rtems__ */
1018#ifdef KTRACE
1019        struct uio *ktruio = NULL;
1020#endif
1021        ssize_t len;
1022        int i, error;
1023
1024        AUDIT_ARG_FD(s);
1025#ifndef __rtems__
1026        rights = &cap_send_rights;
1027        cap_rights_init(&rights, CAP_SEND);
1028        if (mp->msg_name != NULL) {
1029                AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name);
1030                rights = &cap_send_connect_rights;
1031        }
1032#endif /* __rtems__ */
1033        error = getsock_cap(td, s, rights, &fp, NULL, NULL);
1034        if (error != 0) {
1035                m_freem(control);
1036                return (error);
1037        }
1038        so = (struct socket *)fp->f_data;
1039
1040#ifdef KTRACE
1041        if (mp->msg_name != NULL && KTRPOINT(td, KTR_STRUCT))
1042                ktrsockaddr(mp->msg_name);
1043#endif
1044#ifdef MAC
1045        if (mp->msg_name != NULL) {
1046                error = mac_socket_check_connect(td->td_ucred, so,
1047                    mp->msg_name);
1048                if (error != 0) {
1049                        m_freem(control);
1050                        goto bad;
1051                }
1052        }
1053        error = mac_socket_check_send(td->td_ucred, so);
1054        if (error != 0) {
1055                m_freem(control);
1056                goto bad;
1057        }
1058#endif
1059
1060        auio.uio_iov = mp->msg_iov;
1061        auio.uio_iovcnt = mp->msg_iovlen;
1062        auio.uio_segflg = segflg;
1063        auio.uio_rw = UIO_WRITE;
1064        auio.uio_td = td;
1065        auio.uio_offset = 0;                    /* XXX */
1066        auio.uio_resid = 0;
1067        iov = mp->msg_iov;
1068        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
1069                if ((auio.uio_resid += iov->iov_len) < 0) {
1070                        error = EINVAL;
1071                        m_freem(control);
1072                        goto bad;
1073                }
1074        }
1075#ifdef KTRACE
1076        if (KTRPOINT(td, KTR_GENIO))
1077                ktruio = cloneuio(&auio);
1078#endif
1079        len = auio.uio_resid;
1080        error = sosend(so, mp->msg_name, &auio, 0, control, flags, td);
1081        if (error != 0) {
1082                if (auio.uio_resid != len && (error == ERESTART ||
1083                    error == EINTR || error == EWOULDBLOCK))
1084                        error = 0;
1085                /* Generation of SIGPIPE can be controlled per socket */
1086                if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
1087                    !(flags & MSG_NOSIGNAL)) {
1088#ifndef __rtems__
1089                        PROC_LOCK(td->td_proc);
1090                        tdsignal(td, SIGPIPE);
1091                        PROC_UNLOCK(td->td_proc);
1092#else /* __rtems__ */
1093                /* FIXME: Determine if we really want to use signals */
1094#endif /* __rtems__ */
1095                }
1096        }
1097        if (error == 0)
1098                td->td_retval[0] = len - auio.uio_resid;
1099#ifdef KTRACE
1100        if (ktruio != NULL) {
1101                ktruio->uio_resid = td->td_retval[0];
1102                ktrgenio(s, UIO_WRITE, ktruio, error);
1103        }
1104#endif
1105bad:
1106        fdrop(fp, td);
1107        return (error);
1108}
1109
1110#ifdef __rtems__
1111static
1112#endif /* __rtems__ */
1113int
1114sys_sendto(struct thread *td, struct sendto_args *uap)
1115{
1116        struct msghdr msg;
1117        struct iovec aiov;
1118
1119        msg.msg_name = __DECONST(void *, uap->to);
1120        msg.msg_namelen = uap->tolen;
1121        msg.msg_iov = &aiov;
1122        msg.msg_iovlen = 1;
1123        msg.msg_control = 0;
1124#ifdef COMPAT_OLDSOCK
1125        msg.msg_flags = 0;
1126#endif
1127        aiov.iov_base = __DECONST(void *, uap->buf);
1128        aiov.iov_len = uap->len;
1129        return (sendit(td, uap->s, &msg, uap->flags));
1130}
1131#ifdef __rtems__
1132ssize_t
1133sendto(int socket, const void *message, size_t length, int flags,
1134    const struct sockaddr *dest_addr, socklen_t dest_len)
1135{
1136        struct thread *td = rtems_bsd_get_curthread_or_null();
1137        struct sendto_args ua = {
1138                .s = socket,
1139                .buf = (caddr_t) message,
1140                .len = length,
1141                .flags = flags,
1142                .to = dest_addr,
1143                .tolen = dest_len
1144        };
1145        int error;
1146
1147        if (td != NULL) {
1148                error = sys_sendto(td, &ua);
1149        } else {
1150                error = ENOMEM;
1151        }
1152
1153        if (error == 0) {
1154                return td->td_retval[0];
1155        } else {
1156                rtems_set_errno_and_return_minus_one(error);
1157        }
1158}
1159
1160int
1161rtems_bsd_sendto(int socket, struct mbuf *m, int flags,
1162    const struct sockaddr *dest_addr)
1163{
1164        struct thread *td = rtems_bsd_get_curthread_or_null();
1165        struct file *fp;
1166        struct socket *so;
1167        int error;
1168
1169        error = getsock_cap(td->td_proc->p_fd, socket, CAP_WRITE, &fp, NULL, NULL);
1170        if (error)
1171                return (error);
1172        so = (struct socket *)fp->f_data;
1173
1174        if (td != NULL) {
1175                error = sosend(so, __DECONST(struct sockaddr *, dest_addr),
1176                    NULL, m, NULL, flags, td);
1177        } else {
1178                error = ENOMEM;
1179        }
1180
1181        return (error);
1182}
1183#endif /* __rtems__ */
1184
1185#ifndef __rtems__
1186#ifdef COMPAT_OLDSOCK
1187int
1188osend(struct thread *td, struct osend_args *uap)
1189{
1190        struct msghdr msg;
1191        struct iovec aiov;
1192
1193        msg.msg_name = 0;
1194        msg.msg_namelen = 0;
1195        msg.msg_iov = &aiov;
1196        msg.msg_iovlen = 1;
1197        aiov.iov_base = __DECONST(void *, uap->buf);
1198        aiov.iov_len = uap->len;
1199        msg.msg_control = 0;
1200        msg.msg_flags = 0;
1201        return (sendit(td, uap->s, &msg, uap->flags));
1202}
1203
1204int
1205osendmsg(struct thread *td, struct osendmsg_args *uap)
1206{
1207        struct msghdr msg;
1208        struct iovec *iov;
1209        int error;
1210
1211        error = copyin(uap->msg, &msg, sizeof (struct omsghdr));
1212        if (error != 0)
1213                return (error);
1214        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1215        if (error != 0)
1216                return (error);
1217        msg.msg_iov = iov;
1218        msg.msg_flags = MSG_COMPAT;
1219        error = sendit(td, uap->s, &msg, uap->flags);
1220        free(iov, M_IOV);
1221        return (error);
1222}
1223#endif
1224#endif /* __rtems__ */
1225
1226#ifdef __rtems__
1227static
1228#endif /* __rtems__ */
1229int
1230sys_sendmsg(struct thread *td, struct sendmsg_args *uap)
1231{
1232        struct msghdr msg;
1233        struct iovec *iov;
1234        int error;
1235
1236        error = copyin(uap->msg, &msg, sizeof (msg));
1237        if (error != 0)
1238                return (error);
1239        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1240        if (error != 0)
1241                return (error);
1242        msg.msg_iov = iov;
1243#ifdef COMPAT_OLDSOCK
1244        msg.msg_flags = 0;
1245#endif
1246        error = sendit(td, uap->s, &msg, uap->flags);
1247        free(iov, M_IOV);
1248        return (error);
1249}
1250#ifdef __rtems__
1251ssize_t
1252sendmsg(int socket, const struct msghdr *message, int flags)
1253{
1254        struct thread *td = rtems_bsd_get_curthread_or_null();
1255        struct sendmsg_args ua = {
1256                .s = socket,
1257                .msg = message,
1258                .flags = flags
1259        };
1260        int error;
1261
1262        if (td != NULL) {
1263                error = sys_sendmsg(td, &ua);
1264        } else {
1265                error = ENOMEM;
1266        }
1267
1268        if (error == 0) {
1269                return td->td_retval[0];
1270        } else {
1271                rtems_set_errno_and_return_minus_one(error);
1272        }
1273}
1274#endif /* __rtems__ */
1275
1276#ifdef __rtems__
1277static
1278#endif /* __rtems__ */
1279int
1280kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg,
1281    struct mbuf **controlp)
1282{
1283        struct uio auio;
1284        struct iovec *iov;
1285        struct mbuf *control, *m;
1286        caddr_t ctlbuf;
1287        struct file *fp;
1288        struct socket *so;
1289        struct sockaddr *fromsa = NULL;
1290#ifdef KTRACE
1291        struct uio *ktruio = NULL;
1292#endif
1293        ssize_t len;
1294        int error, i;
1295
1296        if (controlp != NULL)
1297                *controlp = NULL;
1298
1299        AUDIT_ARG_FD(s);
1300        error = getsock_cap(td, s, &cap_recv_rights,
1301            &fp, NULL, NULL);
1302        if (error != 0)
1303                return (error);
1304        so = fp->f_data;
1305
1306#ifdef MAC
1307        error = mac_socket_check_receive(td->td_ucred, so);
1308        if (error != 0) {
1309                fdrop(fp, td);
1310                return (error);
1311        }
1312#endif
1313
1314        auio.uio_iov = mp->msg_iov;
1315        auio.uio_iovcnt = mp->msg_iovlen;
1316        auio.uio_segflg = UIO_USERSPACE;
1317        auio.uio_rw = UIO_READ;
1318        auio.uio_td = td;
1319        auio.uio_offset = 0;                    /* XXX */
1320        auio.uio_resid = 0;
1321        iov = mp->msg_iov;
1322        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
1323                if ((auio.uio_resid += iov->iov_len) < 0) {
1324                        fdrop(fp, td);
1325                        return (EINVAL);
1326                }
1327        }
1328#ifdef KTRACE
1329        if (KTRPOINT(td, KTR_GENIO))
1330                ktruio = cloneuio(&auio);
1331#endif
1332        control = NULL;
1333        len = auio.uio_resid;
1334        error = soreceive(so, &fromsa, &auio, NULL,
1335            (mp->msg_control || controlp) ? &control : NULL,
1336            &mp->msg_flags);
1337        if (error != 0) {
1338                if (auio.uio_resid != len && (error == ERESTART ||
1339                    error == EINTR || error == EWOULDBLOCK))
1340                        error = 0;
1341        }
1342        if (fromsa != NULL)
1343                AUDIT_ARG_SOCKADDR(td, AT_FDCWD, fromsa);
1344#ifdef KTRACE
1345        if (ktruio != NULL) {
1346                ktruio->uio_resid = len - auio.uio_resid;
1347                ktrgenio(s, UIO_READ, ktruio, error);
1348        }
1349#endif
1350        if (error != 0)
1351                goto out;
1352        td->td_retval[0] = len - auio.uio_resid;
1353        if (mp->msg_name) {
1354                len = mp->msg_namelen;
1355                if (len <= 0 || fromsa == NULL)
1356                        len = 0;
1357                else {
1358                        /* save sa_len before it is destroyed by MSG_COMPAT */
1359                        len = MIN(len, fromsa->sa_len);
1360#ifdef COMPAT_OLDSOCK
1361                        if (mp->msg_flags & MSG_COMPAT)
1362                                ((struct osockaddr *)fromsa)->sa_family =
1363                                    fromsa->sa_family;
1364#endif
1365                        if (fromseg == UIO_USERSPACE) {
1366                                error = copyout(fromsa, mp->msg_name,
1367                                    (unsigned)len);
1368                                if (error != 0)
1369                                        goto out;
1370                        } else
1371                                bcopy(fromsa, mp->msg_name, len);
1372                }
1373                mp->msg_namelen = len;
1374        }
1375        if (mp->msg_control && controlp == NULL) {
1376#ifdef COMPAT_OLDSOCK
1377                /*
1378                 * We assume that old recvmsg calls won't receive access
1379                 * rights and other control info, esp. as control info
1380                 * is always optional and those options didn't exist in 4.3.
1381                 * If we receive rights, trim the cmsghdr; anything else
1382                 * is tossed.
1383                 */
1384                if (control && mp->msg_flags & MSG_COMPAT) {
1385                        if (mtod(control, struct cmsghdr *)->cmsg_level !=
1386                            SOL_SOCKET ||
1387                            mtod(control, struct cmsghdr *)->cmsg_type !=
1388                            SCM_RIGHTS) {
1389                                mp->msg_controllen = 0;
1390                                goto out;
1391                        }
1392                        control->m_len -= sizeof (struct cmsghdr);
1393                        control->m_data += sizeof (struct cmsghdr);
1394                }
1395#endif
1396                ctlbuf = mp->msg_control;
1397                len = mp->msg_controllen;
1398                mp->msg_controllen = 0;
1399                for (m = control; m != NULL && len >= m->m_len; m = m->m_next) {
1400                        if ((error = copyout(mtod(m, caddr_t), ctlbuf,
1401                            m->m_len)) != 0)
1402                                goto out;
1403
1404                        ctlbuf += m->m_len;
1405                        len -= m->m_len;
1406                        mp->msg_controllen += m->m_len;
1407                }
1408                if (m != NULL) {
1409                        mp->msg_flags |= MSG_CTRUNC;
1410                        m_dispose_extcontrolm(m);
1411                }
1412        }
1413out:
1414        fdrop(fp, td);
1415#ifdef KTRACE
1416        if (fromsa && KTRPOINT(td, KTR_STRUCT))
1417                ktrsockaddr(fromsa);
1418#endif
1419        free(fromsa, M_SONAME);
1420
1421        if (error == 0 && controlp != NULL)
1422                *controlp = control;
1423        else if (control != NULL) {
1424                if (error != 0)
1425                        m_dispose_extcontrolm(control);
1426                m_freem(control);
1427        }
1428
1429        return (error);
1430}
1431
1432static int
1433recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp)
1434{
1435        int error;
1436
1437        error = kern_recvit(td, s, mp, UIO_USERSPACE, NULL);
1438        if (error != 0)
1439                return (error);
1440        if (namelenp != NULL) {
1441                error = copyout(&mp->msg_namelen, namelenp, sizeof (socklen_t));
1442#ifdef COMPAT_OLDSOCK
1443                if (mp->msg_flags & MSG_COMPAT)
1444                        error = 0;      /* old recvfrom didn't check */
1445#endif
1446        }
1447        return (error);
1448}
1449
1450#ifdef __rtems__
1451static
1452#endif /* __rtems__ */
1453int
1454sys_recvfrom(struct thread *td, struct recvfrom_args *uap)
1455{
1456        struct msghdr msg;
1457        struct iovec aiov;
1458        int error;
1459
1460        if (uap->fromlenaddr) {
1461                error = copyin(uap->fromlenaddr,
1462                    &msg.msg_namelen, sizeof (msg.msg_namelen));
1463                if (error != 0)
1464                        goto done2;
1465        } else {
1466                msg.msg_namelen = 0;
1467        }
1468        msg.msg_name = uap->from;
1469        msg.msg_iov = &aiov;
1470        msg.msg_iovlen = 1;
1471        aiov.iov_base = uap->buf;
1472        aiov.iov_len = uap->len;
1473        msg.msg_control = 0;
1474        msg.msg_flags = uap->flags;
1475        error = recvit(td, uap->s, &msg, uap->fromlenaddr);
1476done2:
1477        return (error);
1478}
1479#ifdef __rtems__
1480ssize_t
1481recvfrom(int socket, void *__restrict buffer, size_t length, int flags,
1482    struct sockaddr *__restrict address, socklen_t *__restrict address_len)
1483{
1484        struct thread *td = rtems_bsd_get_curthread_or_null();
1485        struct recvfrom_args ua = {
1486                .s = socket,
1487                .buf = buffer,
1488                .len = length,
1489                .flags = flags,
1490                .from = address,
1491                .fromlenaddr = address_len
1492        };
1493        int error;
1494
1495        if (td != NULL) {
1496                error = sys_recvfrom(td, &ua);
1497        } else {
1498                error = ENOMEM;
1499        }
1500
1501        if (error == 0) {
1502                return td->td_retval[0];
1503        } else {
1504                rtems_set_errno_and_return_minus_one(error);
1505        }
1506}
1507#endif /* __rtems__ */
1508
1509#ifndef __rtems__
1510#ifdef COMPAT_OLDSOCK
1511int
1512orecvfrom(struct thread *td, struct recvfrom_args *uap)
1513{
1514
1515        uap->flags |= MSG_COMPAT;
1516        return (sys_recvfrom(td, uap));
1517}
1518#endif
1519
1520#ifdef COMPAT_OLDSOCK
1521int
1522orecv(struct thread *td, struct orecv_args *uap)
1523{
1524        struct msghdr msg;
1525        struct iovec aiov;
1526
1527        msg.msg_name = 0;
1528        msg.msg_namelen = 0;
1529        msg.msg_iov = &aiov;
1530        msg.msg_iovlen = 1;
1531        aiov.iov_base = uap->buf;
1532        aiov.iov_len = uap->len;
1533        msg.msg_control = 0;
1534        msg.msg_flags = uap->flags;
1535        return (recvit(td, uap->s, &msg, NULL));
1536}
1537
1538/*
1539 * Old recvmsg.  This code takes advantage of the fact that the old msghdr
1540 * overlays the new one, missing only the flags, and with the (old) access
1541 * rights where the control fields are now.
1542 */
1543int
1544orecvmsg(struct thread *td, struct orecvmsg_args *uap)
1545{
1546        struct msghdr msg;
1547        struct iovec *iov;
1548        int error;
1549
1550        error = copyin(uap->msg, &msg, sizeof (struct omsghdr));
1551        if (error != 0)
1552                return (error);
1553        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1554        if (error != 0)
1555                return (error);
1556        msg.msg_flags = uap->flags | MSG_COMPAT;
1557        msg.msg_iov = iov;
1558        error = recvit(td, uap->s, &msg, &uap->msg->msg_namelen);
1559        if (msg.msg_controllen && error == 0)
1560                error = copyout(&msg.msg_controllen,
1561                    &uap->msg->msg_accrightslen, sizeof (int));
1562        free(iov, M_IOV);
1563        return (error);
1564}
1565#endif
1566#endif /* __rtems__ */
1567
1568#ifdef __rtems__
1569static
1570#endif /* __rtems__ */
1571int
1572sys_recvmsg(struct thread *td, struct recvmsg_args *uap)
1573{
1574        struct msghdr msg;
1575        struct iovec *uiov, *iov;
1576        int error;
1577
1578        error = copyin(uap->msg, &msg, sizeof (msg));
1579        if (error != 0)
1580                return (error);
1581        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1582        if (error != 0)
1583                return (error);
1584        msg.msg_flags = uap->flags;
1585#ifdef COMPAT_OLDSOCK
1586        msg.msg_flags &= ~MSG_COMPAT;
1587#endif
1588        uiov = msg.msg_iov;
1589        msg.msg_iov = iov;
1590        error = recvit(td, uap->s, &msg, NULL);
1591        if (error == 0) {
1592                msg.msg_iov = uiov;
1593                error = copyout(&msg, uap->msg, sizeof(msg));
1594        }
1595        free(iov, M_IOV);
1596        return (error);
1597}
1598#ifdef __rtems__
1599ssize_t
1600recvmsg(int socket, struct msghdr *message, int flags)
1601{
1602        struct thread *td = rtems_bsd_get_curthread_or_null();
1603        struct recvmsg_args ua = {
1604                .s = socket,
1605                .msg = message,
1606                .flags = flags
1607        };
1608        int error;
1609
1610        if (td != NULL) {
1611                error = sys_recvmsg(td, &ua);
1612        } else {
1613                error = ENOMEM;
1614        }
1615
1616        if (error == 0) {
1617                return td->td_retval[0];
1618        } else {
1619                rtems_set_errno_and_return_minus_one(error);
1620        }
1621}
1622#endif /* __rtems__ */
1623
1624#ifdef __rtems__
1625static
1626#endif /* __rtems__ */
1627int
1628sys_shutdown(struct thread *td, struct shutdown_args *uap)
1629{
1630
1631        return (kern_shutdown(td, uap->s, uap->how));
1632}
1633
1634int
1635kern_shutdown(struct thread *td, int s, int how)
1636{
1637        struct socket *so;
1638        struct file *fp;
1639        int error;
1640
1641        AUDIT_ARG_FD(s);
1642        error = getsock_cap(td, s, &cap_shutdown_rights,
1643            &fp, NULL, NULL);
1644        if (error == 0) {
1645                so = fp->f_data;
1646                error = soshutdown(so, how);
1647#ifndef __rtems__
1648                /*
1649                 * Previous versions did not return ENOTCONN, but 0 in
1650                 * case the socket was not connected. Some important
1651                 * programs like syslogd up to r279016, 2015-02-19,
1652                 * still depend on this behavior.
1653                 */
1654                if (error == ENOTCONN &&
1655                    td->td_proc->p_osrel < P_OSREL_SHUTDOWN_ENOTCONN)
1656                        error = 0;
1657#endif /* __rtems__ */
1658                fdrop(fp, td);
1659        }
1660        return (error);
1661}
1662#ifdef __rtems__
1663int
1664shutdown(int socket, int how)
1665{
1666        struct shutdown_args ua = {
1667                .s = socket,
1668                .how = how
1669        };
1670        int error = sys_shutdown(NULL, &ua);
1671
1672        return rtems_bsd_error_to_status_and_errno(error);
1673}
1674#endif /* __rtems__ */
1675
1676#ifdef __rtems__
1677static
1678#endif /* __rtems__ */
1679int
1680sys_setsockopt(struct thread *td, struct setsockopt_args *uap)
1681{
1682
1683        return (kern_setsockopt(td, uap->s, uap->level, uap->name,
1684            uap->val, UIO_USERSPACE, uap->valsize));
1685}
1686#ifdef __rtems__
1687int
1688setsockopt(int socket, int level, int option_name, const void *option_value,
1689    socklen_t option_len)
1690{
1691        struct thread *td = rtems_bsd_get_curthread_or_null();
1692        struct setsockopt_args ua = {
1693                .s = socket,
1694                .level = level,
1695                .name = option_name,
1696                .val = __DECONST(void *, option_value),
1697                .valsize = option_len
1698        };
1699        int error;
1700
1701        if (td != NULL) {
1702                error = sys_setsockopt(td, &ua);
1703        } else {
1704                error = ENOMEM;
1705        }
1706
1707        return rtems_bsd_error_to_status_and_errno(error);
1708}
1709#endif /* __rtems__ */
1710
1711int
1712kern_setsockopt(struct thread *td, int s, int level, int name, const void *val,
1713    enum uio_seg valseg, socklen_t valsize)
1714{
1715        struct socket *so;
1716        struct file *fp;
1717        struct sockopt sopt;
1718        int error;
1719
1720        if (val == NULL && valsize != 0)
1721                return (EFAULT);
1722        if ((int)valsize < 0)
1723                return (EINVAL);
1724
1725        sopt.sopt_dir = SOPT_SET;
1726        sopt.sopt_level = level;
1727        sopt.sopt_name = name;
1728        sopt.sopt_val = __DECONST(void *, val);
1729        sopt.sopt_valsize = valsize;
1730        switch (valseg) {
1731        case UIO_USERSPACE:
1732                sopt.sopt_td = td;
1733                break;
1734        case UIO_SYSSPACE:
1735                sopt.sopt_td = NULL;
1736                break;
1737        default:
1738                panic("kern_setsockopt called with bad valseg");
1739        }
1740
1741        AUDIT_ARG_FD(s);
1742        error = getsock_cap(td, s, &cap_setsockopt_rights,
1743            &fp, NULL, NULL);
1744        if (error == 0) {
1745                so = fp->f_data;
1746                error = sosetopt(so, &sopt);
1747                fdrop(fp, td);
1748        }
1749        return(error);
1750}
1751
1752#ifdef __rtems__
1753static int kern_getsockopt( struct thread *td, int s, int level, int name,
1754    void *val, enum uio_seg valseg, socklen_t *valsize);
1755
1756static
1757#endif /* __rtems__ */
1758int
1759sys_getsockopt(struct thread *td, struct getsockopt_args *uap)
1760{
1761        socklen_t valsize;
1762        int error;
1763
1764        if (uap->val) {
1765                error = copyin(uap->avalsize, &valsize, sizeof (valsize));
1766                if (error != 0)
1767                        return (error);
1768        }
1769
1770        error = kern_getsockopt(td, uap->s, uap->level, uap->name,
1771            uap->val, UIO_USERSPACE, &valsize);
1772
1773        if (error == 0)
1774                error = copyout(&valsize, uap->avalsize, sizeof (valsize));
1775        return (error);
1776}
1777#ifdef __rtems__
1778int
1779getsockopt(int socket, int level, int option_name, void *__restrict
1780    option_value, socklen_t *__restrict option_len)
1781{
1782        struct thread *td = rtems_bsd_get_curthread_or_null();
1783        struct getsockopt_args ua = {
1784                .s = socket,
1785                .level = level,
1786                .name = option_name,
1787                .val = (caddr_t) option_value,
1788                .avalsize = option_len
1789        };
1790        int error;
1791
1792        if (td != NULL) {
1793                error = sys_getsockopt(td, &ua);
1794        } else {
1795                error = ENOMEM;
1796        }
1797
1798        return rtems_bsd_error_to_status_and_errno(error);
1799}
1800#endif /* __rtems__ */
1801
1802/*
1803 * Kernel version of getsockopt.
1804 * optval can be a userland or userspace. optlen is always a kernel pointer.
1805 */
1806int
1807kern_getsockopt(struct thread *td, int s, int level, int name, void *val,
1808    enum uio_seg valseg, socklen_t *valsize)
1809{
1810        struct socket *so;
1811        struct file *fp;
1812        struct sockopt sopt;
1813        int error;
1814
1815        if (val == NULL)
1816                *valsize = 0;
1817        if ((int)*valsize < 0)
1818                return (EINVAL);
1819
1820        sopt.sopt_dir = SOPT_GET;
1821        sopt.sopt_level = level;
1822        sopt.sopt_name = name;
1823        sopt.sopt_val = val;
1824        sopt.sopt_valsize = (size_t)*valsize; /* checked non-negative above */
1825        switch (valseg) {
1826        case UIO_USERSPACE:
1827                sopt.sopt_td = td;
1828                break;
1829        case UIO_SYSSPACE:
1830                sopt.sopt_td = NULL;
1831                break;
1832        default:
1833                panic("kern_getsockopt called with bad valseg");
1834        }
1835
1836        AUDIT_ARG_FD(s);
1837        error = getsock_cap(td, s, &cap_getsockopt_rights,
1838            &fp, NULL, NULL);
1839        if (error == 0) {
1840                so = fp->f_data;
1841                error = sogetopt(so, &sopt);
1842                *valsize = sopt.sopt_valsize;
1843                fdrop(fp, td);
1844        }
1845        return (error);
1846}
1847
1848/*
1849 * getsockname1() - Get socket name.
1850 */
1851static int
1852getsockname1(struct thread *td, struct getsockname_args *uap, int compat)
1853{
1854        struct sockaddr *sa;
1855        socklen_t len;
1856        int error;
1857
1858        error = copyin(uap->alen, &len, sizeof(len));
1859        if (error != 0)
1860                return (error);
1861
1862        error = kern_getsockname(td, uap->fdes, &sa, &len);
1863        if (error != 0)
1864                return (error);
1865
1866        if (len != 0) {
1867#ifdef COMPAT_OLDSOCK
1868                if (compat)
1869                        ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1870#endif
1871                error = copyout(sa, uap->asa, (u_int)len);
1872        }
1873        free(sa, M_SONAME);
1874        if (error == 0)
1875                error = copyout(&len, uap->alen, sizeof(len));
1876        return (error);
1877}
1878#ifdef __rtems__
1879int
1880getsockname(int socket, struct sockaddr *__restrict address,
1881    socklen_t *__restrict address_len)
1882{
1883        struct thread *td = rtems_bsd_get_curthread_or_null();
1884        struct getsockname_args ua = {
1885                .fdes = socket,
1886                .asa = address,
1887                .alen = address_len
1888        };
1889        int error;
1890
1891        if (td != NULL) {
1892                error = getsockname1(td, &ua, 0);
1893        } else {
1894                error = ENOMEM;
1895        }
1896
1897        return rtems_bsd_error_to_status_and_errno(error);
1898}
1899#endif /* __rtems__ */
1900
1901int
1902kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
1903    socklen_t *alen)
1904{
1905        struct socket *so;
1906        struct file *fp;
1907        socklen_t len;
1908        int error;
1909
1910        AUDIT_ARG_FD(fd);
1911        error = getsock_cap(td, fd, &cap_getsockname_rights,
1912            &fp, NULL, NULL);
1913        if (error != 0)
1914                return (error);
1915        so = fp->f_data;
1916        *sa = NULL;
1917        CURVNET_SET(so->so_vnet);
1918        error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, sa);
1919        CURVNET_RESTORE();
1920        if (error != 0)
1921                goto bad;
1922        if (*sa == NULL)
1923                len = 0;
1924        else
1925                len = MIN(*alen, (*sa)->sa_len);
1926        *alen = len;
1927#ifdef KTRACE
1928        if (KTRPOINT(td, KTR_STRUCT))
1929                ktrsockaddr(*sa);
1930#endif
1931bad:
1932        fdrop(fp, td);
1933        if (error != 0 && *sa != NULL) {
1934                free(*sa, M_SONAME);
1935                *sa = NULL;
1936        }
1937        return (error);
1938}
1939
1940#ifndef __rtems__
1941int
1942sys_getsockname(struct thread *td, struct getsockname_args *uap)
1943{
1944
1945        return (getsockname1(td, uap, 0));
1946}
1947
1948#ifdef COMPAT_OLDSOCK
1949int
1950ogetsockname(struct thread *td, struct getsockname_args *uap)
1951{
1952
1953        return (getsockname1(td, uap, 1));
1954}
1955#endif /* COMPAT_OLDSOCK */
1956#endif /* __rtems__ */
1957
1958#ifdef __rtems__
1959static int
1960kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
1961    socklen_t *alen);
1962#endif /* __rtems__ */
1963/*
1964 * getpeername1() - Get name of peer for connected socket.
1965 */
1966static int
1967getpeername1(struct thread *td, struct getpeername_args *uap, int compat)
1968{
1969        struct sockaddr *sa;
1970        socklen_t len;
1971        int error;
1972
1973        error = copyin(uap->alen, &len, sizeof (len));
1974        if (error != 0)
1975                return (error);
1976
1977        error = kern_getpeername(td, uap->fdes, &sa, &len);
1978        if (error != 0)
1979                return (error);
1980
1981        if (len != 0) {
1982#ifdef COMPAT_OLDSOCK
1983                if (compat)
1984                        ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1985#endif
1986                error = copyout(sa, uap->asa, (u_int)len);
1987        }
1988        free(sa, M_SONAME);
1989        if (error == 0)
1990                error = copyout(&len, uap->alen, sizeof(len));
1991        return (error);
1992}
1993#ifdef __rtems__
1994int
1995getpeername(int socket, struct sockaddr *__restrict address,
1996    socklen_t *__restrict address_len)
1997{
1998        struct thread *td = rtems_bsd_get_curthread_or_null();
1999        struct getpeername_args ua = {
2000                .fdes = socket,
2001                .asa = address,
2002                .alen = address_len
2003        };
2004        int error;
2005
2006        if (td != NULL) {
2007                error = getpeername1(td, &ua, 0);
2008        } else {
2009                error = ENOMEM;
2010        }
2011
2012        return rtems_bsd_error_to_status_and_errno(error);
2013}
2014#endif /* __rtems__ */
2015
2016int
2017kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
2018    socklen_t *alen)
2019{
2020        struct socket *so;
2021        struct file *fp;
2022        socklen_t len;
2023        int error;
2024
2025        AUDIT_ARG_FD(fd);
2026        error = getsock_cap(td, fd, &cap_getpeername_rights,
2027            &fp, NULL, NULL);
2028        if (error != 0)
2029                return (error);
2030        so = fp->f_data;
2031        if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
2032                error = ENOTCONN;
2033                goto done;
2034        }
2035        *sa = NULL;
2036        CURVNET_SET(so->so_vnet);
2037        error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, sa);
2038        CURVNET_RESTORE();
2039        if (error != 0)
2040                goto bad;
2041        if (*sa == NULL)
2042                len = 0;
2043        else
2044                len = MIN(*alen, (*sa)->sa_len);
2045        *alen = len;
2046#ifdef KTRACE
2047        if (KTRPOINT(td, KTR_STRUCT))
2048                ktrsockaddr(*sa);
2049#endif
2050bad:
2051        if (error != 0 && *sa != NULL) {
2052                free(*sa, M_SONAME);
2053                *sa = NULL;
2054        }
2055done:
2056        fdrop(fp, td);
2057        return (error);
2058}
2059
2060#ifndef __rtems__
2061int
2062sys_getpeername(struct thread *td, struct getpeername_args *uap)
2063{
2064
2065        return (getpeername1(td, uap, 0));
2066}
2067
2068#ifdef COMPAT_OLDSOCK
2069int
2070ogetpeername(struct thread *td, struct ogetpeername_args *uap)
2071{
2072
2073        /* XXX uap should have type `getpeername_args *' to begin with. */
2074        return (getpeername1(td, (struct getpeername_args *)uap, 1));
2075}
2076#endif /* COMPAT_OLDSOCK */
2077#endif /* __rtems__ */
2078
2079static int
2080sockargs(struct mbuf **mp, char *buf, socklen_t buflen, int type)
2081{
2082        struct sockaddr *sa;
2083        struct mbuf *m;
2084        int error;
2085
2086        if (buflen > MLEN) {
2087#ifdef COMPAT_OLDSOCK
2088                if (type == MT_SONAME && buflen <= 112)
2089                        buflen = MLEN;          /* unix domain compat. hack */
2090                else
2091#endif
2092                        if (buflen > MCLBYTES)
2093                                return (EINVAL);
2094        }
2095        m = m_get2(buflen, M_WAITOK, type, 0);
2096        m->m_len = buflen;
2097        error = copyin(buf, mtod(m, void *), buflen);
2098        if (error != 0)
2099                (void) m_free(m);
2100        else {
2101                *mp = m;
2102                if (type == MT_SONAME) {
2103                        sa = mtod(m, struct sockaddr *);
2104
2105#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
2106                        if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
2107                                sa->sa_family = sa->sa_len;
2108#endif
2109                        sa->sa_len = buflen;
2110                }
2111        }
2112        return (error);
2113}
2114
2115int
2116getsockaddr(struct sockaddr **namp, const struct sockaddr *uaddr, size_t len)
2117{
2118        struct sockaddr *sa;
2119#ifndef __rtems__
2120        int error;
2121#endif /* __rtems__ */
2122
2123        if (len > SOCK_MAXADDRLEN)
2124                return (ENAMETOOLONG);
2125        if (len < offsetof(struct sockaddr, sa_data[0]))
2126                return (EINVAL);
2127#ifndef __rtems__
2128        sa = malloc(len, M_SONAME, M_WAITOK);
2129        error = copyin(uaddr, sa, len);
2130        if (error != 0) {
2131                free(sa, M_SONAME);
2132        } else {
2133#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
2134                if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
2135                        sa->sa_family = sa->sa_len;
2136#endif
2137                sa->sa_len = len;
2138                *namp = sa;
2139        }
2140        return (error);
2141#else /* __rtems__ */
2142        sa = memcpy(*namp, uaddr, len);
2143        sa->sa_len = len;
2144        return (0);
2145#endif /* __rtems__ */
2146}
2147
2148/*
2149 * Dispose of externalized rights from an SCM_RIGHTS message.  This function
2150 * should be used in error or truncation cases to avoid leaking file descriptors
2151 * into the recipient's (the current thread's) table.
2152 */
2153void
2154m_dispose_extcontrolm(struct mbuf *m)
2155{
2156        struct cmsghdr *cm;
2157        struct file *fp;
2158        struct thread *td;
2159        socklen_t clen, datalen;
2160        int error, fd, *fds, nfd;
2161
2162        td = curthread;
2163        for (; m != NULL; m = m->m_next) {
2164                if (m->m_type != MT_EXTCONTROL)
2165                        continue;
2166                cm = mtod(m, struct cmsghdr *);
2167                clen = m->m_len;
2168                while (clen > 0) {
2169                        if (clen < sizeof(*cm))
2170                                panic("%s: truncated mbuf %p", __func__, m);
2171                        datalen = CMSG_SPACE(cm->cmsg_len - CMSG_SPACE(0));
2172                        if (clen < datalen)
2173                                panic("%s: truncated mbuf %p", __func__, m);
2174
2175                        if (cm->cmsg_level == SOL_SOCKET &&
2176                            cm->cmsg_type == SCM_RIGHTS) {
2177                                fds = (int *)CMSG_DATA(cm);
2178                                nfd = (cm->cmsg_len - CMSG_SPACE(0)) /
2179                                    sizeof(int);
2180
2181                                while (nfd-- > 0) {
2182                                        fd = *fds++;
2183                                        error = fget(td, fd, &cap_no_rights,
2184                                            &fp);
2185                                        if (error == 0)
2186                                                fdclose(td, fp, fd);
2187                                }
2188                        }
2189                        clen -= datalen;
2190                        cm = (struct cmsghdr *)((uint8_t *)cm + datalen);
2191                }
2192                m_chtype(m, MT_CONTROL);
2193        }
2194}
Note: See TracBrowser for help on using the repository browser.